package com.gobang.websocket.dispatcher;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gobang.common.constant.BusinessErrorCode;
import com.gobang.common.exception.BusinessException;
import com.gobang.websocket.handler.HeartbeatMessageHandler;
import com.gobang.websocket.model.WebSocketEnvelope;
import com.gobang.websocket.service.WebSocketPushService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.WebSocketSession;

/**
 * WebSocket 消息调度器
 *
 * 负责 JSON 解析与基于 type 的路由。
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class WebSocketMessageDispatcher {

    private final ObjectMapper objectMapper;
    private final HeartbeatMessageHandler heartbeatMessageHandler;
    private final WebSocketPushService webSocketPushService;

    /**
     * 统一入口：分发消息
     *
     * @param session 当前会话
     * @param payload 文本消息内容
     */
    public void dispatch(WebSocketSession session, String payload) {
        try {
            WebSocketEnvelope envelope = objectMapper.readValue(payload, WebSocketEnvelope.class);
            if (envelope == null || !StringUtils.hasText(envelope.getType())) {
                throw new BusinessException(BusinessErrorCode.WEBSOCKET_MESSAGE_FORMAT_ERROR, "消息type不能为空");
            }

            String type = envelope.getType();
            JsonNode data = envelope.getData();
            if (data != null && !data.isObject()) {
                throw new BusinessException(BusinessErrorCode.WEBSOCKET_MESSAGE_FORMAT_ERROR, "消息data必须为Json对象");
            }

            switch (type) {
                case "ping" -> heartbeatMessageHandler.handle(session, data);
                default -> {
                    log.warn("收到未知类型的 WebSocket 消息: type={}", type);
                    webSocketPushService.sendError(session,
                            BusinessErrorCode.WEBSOCKET_MESSAGE_FORMAT_ERROR.getCode(),
                            "未知消息类型: " + type);
                }
            }
        } catch (BusinessException e) {
            log.warn("WebSocket 消息业务处理异常: code={}, message={}", e.getCode(), e.getMessage());
            webSocketPushService.sendError(session, e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("WebSocket 消息处理异常", e);
            webSocketPushService.sendError(session,
                    BusinessErrorCode.SYSTEM_ERROR.getCode(),
                    "服务器内部错误");
        }
    }
}
